<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 考点：作用域 ，this , 变量提升（函数无调用者，this ===> window）
        var a = 10;

        function test() {
            a = 100;
            console.log(a); // 100 
            console.log(this.a); // 10   this ===> window
            var a;
            console.log(a); // 100
        }
        test(); // this.test
        //***************************************************************

        // 考点：自执行 作用域 预解析
        (function () {
            var a = b = 3; // b = 3; var a = b
        })()
        console.log(a); // 报错 全局变量中没有 a
        console.log(b); // 3    b 相当于全局变量

        // 考点： 事件循环 等待队列 异步 单线程
        for (var i = 1; i <= 3; i++) {
            setTimeout(function () {
                console.log(i); // 3 个 4 // let 123 作用域 函数作用域 全局作用域 块级作用域
            }, 0)
        }
        //***************************************************************

        // 考点：作用域 变量提升 参数
        // function fun(){ // 不带参，就是 undefined 456
        /* function fun(n){
            // var n = undefined; n = n // 参数赋值
            console.log(n); // 123
            var n = 456;    // 修改 n
            console.log(n); // 456 
        }
        var n = 123;
        fun(n);  */
        //***************************************************************

        /* function fun(){  // 不接收参数
            console.log(n); // 123
            n = 456;        // 不 var n
            console.log(n); // 456 
        }
        var n = 123;
        fun(n);  */
        //***************************************************************

        // var fun = 123; 
        /* var fun = undefined;
           function fun = function */
        function fun() { // 不接收参数
            console.log(fun); // [Funtion:fun]
            fun = 456;
            console.log(fun); // 456 
        }
        fun(n);
        var fun = 123;
        //***************************************************************

        // 考点：预解析 作用域
        /* var n = 123;    //  全局
        function f1() {
            console.log(n);
        }

        function f2() {
            var n = 456;
            f1();   //  f1 在 f2 中执行，作用域，无调用者，f1 作用域是 window
        }
        f2(); // 无调用者 window
        console.log(n) */
        //***************************************************************

        //***************************************************************
        // arguments js 内置对象 参数数组
        function arg() {
            console.log(arguments, arguments.length);
        }
        arg(1, 2, 3, 'a', 'b', 'c')
        //***************************************************************

        var length = 100;

        function f1() {
            console.log(this.length);
        }
        var obj = {
            x: 10,
            f2: function (f1) {
                f1(); // * 无调用者 this == window 100
                arguments[0](); // arguments[0] == f1   无调用者 作用域 arguments 对象 this.length 打印的是 arguments 的长度
            }
        }
        obj.f2(f1, 1);
        //***************************************************************

        // 考点 预解析 字面量 作用域
        function f() {
            console.log(this.a); //  this ===> window hello
        }
        var obj = {
            a: 2,
            f: f
        }
        var f2 = obj.f;
        var a = 'hello'
        f2(); // 无调用者 this ==> window  f2 = obj.f  ===> {console.log(this.a)} this.a ===> 全局
        obj.f(); //  有调用者 this.a === 2
        //***************************************************************

        // 考点：预解析 字面量 apply arguments 作用域
        function f(s) {
            console.log(this.a, s); //  s=3    this ==> obj
            return this.a + s;
        }
        var obj = {
            a: 2
        }
        var f2 = function () { // 无形参接收 用 arguments 接收
            return f.call(obj, ...arguments)
            // return f.apply(obj, arguments)
        };
        var b = f2(3);
        console.log(b);
        //***************************************************************

        //**** apply ****************************************************
        // apply 执行一个函数
        var o = {
            name: 'abc'
        }

        /* function test() {
            console.log(this.name);
        }
        test();
        test.apply(o); */
        //****************************************************************

        //**** call ******************************************************
        var o = {
            name: 'abc'
        }

        function test(a, b) {
            console.log(this.name, a, b);
        }
        test();
        test.apply(o, [1, 2]);
        test.call(o, 1, 2)
        //*****************************************************************

        // 考点：预解析 var fun
        function b() {
            // a = fun
            console.log(a); // ƒ a() {} // fn var=undefined fun=fn
            var a = 10;

            function a() {}
            a = 100;
            console.log(a)
        }
        b();
    </script>
</body>

</html>